home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / minix / libsrc~1.z / libsrc~1 / strtoul.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-12-28  |  1.9 KB  |  82 lines

  1. /* origonal from norbert schelenkar's stdio */
  2. /* eff hacks    ++jrb */
  3.  
  4. #include <ctype.h>
  5. #include <errno.h>
  6. #include <limits.h>
  7. #include <stdlib.h>
  8.  
  9. /* defines to avoid long muls on a lowly 68k */
  10. #define _TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  11. #define _BASEMUL(B, X) \
  12.     (((B) == 10) ? _TEN_MUL((X)) : (((B) == 16) ? ((X) << 4) : ((X) << 3)))
  13.  
  14. unsigned long int strtoul(nptr, endptr, base)
  15. register _CONST char *nptr;
  16. char **endptr;
  17. int base;
  18. {
  19.     register short c;
  20.     unsigned long result = 0L;
  21.     unsigned long limit;
  22.     short negative = 0;
  23.     short overflow = 0;
  24.     short digit;
  25.     
  26.     while ((c = *nptr) && isspace(c))    /* skip leading white space */
  27.     nptr++;
  28.     if ((c = *nptr) == '+' || c == '-') {    /* handle signs */
  29.     negative = (c == '-');
  30.     nptr++;
  31.     }
  32.     if (base == 0) {            /* determine base if unknown */
  33.     base = 10;
  34.     if (*nptr == '0') {
  35.         base = 8;
  36.         nptr++;
  37.         if ((c = *nptr) == 'x' || c == 'X') {
  38.         base = 16;
  39.         nptr++;
  40.         }
  41.     }
  42.     }
  43.     else
  44.     if (base == 16 && *nptr == '0') { /* discard 0x/0X prefix if hex */
  45.         nptr++;
  46.         if ((c = *nptr == 'x') || c == 'X')
  47.         nptr++;
  48.     }
  49.     
  50.     limit = (base == 10) ? ULONG_MAX/10L :     /* ensure no overflow */
  51.     ((base == 8) ? ULONG_MAX/8L : ULONG_MAX/16L);
  52.     
  53.     nptr--;                /* convert the number */
  54.     while (c = *++nptr) {
  55.     if (isdigit(c))
  56.         digit = c - '0';
  57.     else
  58.         digit = c - (isupper(c) ? 'A' : 'a') + 10;
  59.     if (digit < 0 || digit >= base)
  60.         break;
  61.     if (result > limit)
  62.         overflow = 1;
  63.     if (!overflow) {
  64.         result = _BASEMUL(base, result);
  65.         if (digit > ULONG_MAX - result)
  66.         overflow = 1;
  67.         else    
  68.         result += digit;
  69.     }
  70.     }
  71.     if (negative && !overflow)    /* BIZARRE, but ANSI says we should do this! */
  72.     result = 0L - result;
  73.     if (overflow) {
  74.     errno = ERANGE;
  75.     result = ULONG_MAX;
  76.     }
  77.     
  78.     if (endptr != NULL)            /* point at tail */
  79.     *endptr = (char *)nptr;
  80.     return result;
  81. }
  82.